ART: Fix invalid access and DCHECK in verifier

If we get a throwing failure when setting types from the signature,
the work instruction index is still invalid. Do not try to copy the
line then.

As a throwing failure might happen in the above instance, but the
flow analysis expects to have a cleared failure flag before processing
each instruction, clear the flag.

Bug: 21645819
Bug: 22080519
Change-Id: I224c4dad98fa5bb50e62210f0ee30c0dd020e3a6
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 1f7dd58..085f741 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -385,7 +385,7 @@
                                bool allow_thread_suspension)
     : self_(self),
       reg_types_(can_load_classes),
-      work_insn_idx_(-1),
+      work_insn_idx_(DexFile::kDexNoIndex),
       dex_method_idx_(dex_method_idx),
       mirror_method_(method),
       method_access_flags_(method_access_flags),
@@ -409,7 +409,8 @@
       has_check_casts_(false),
       has_virtual_or_interface_invokes_(false),
       verify_to_dump_(verify_to_dump),
-      allow_thread_suspension_(allow_thread_suspension) {
+      allow_thread_suspension_(allow_thread_suspension),
+      link_(nullptr) {
   self->PushVerifier(this);
   DCHECK(class_def != nullptr);
 }
@@ -599,12 +600,16 @@
         // We need to save the work_line if the instruction wasn't throwing before. Otherwise we'll
         // try to merge garbage.
         // Note: this assumes that Fail is called before we do any work_line modifications.
-        const uint16_t* insns = code_item_->insns_ + work_insn_idx_;
-        const Instruction* inst = Instruction::At(insns);
-        int opcode_flags = Instruction::FlagsOf(inst->Opcode());
+        // Note: this can fail before we touch any instruction, for the signature of a method. So
+        //       add a check.
+        if (work_insn_idx_ < DexFile::kDexNoIndex) {
+          const uint16_t* insns = code_item_->insns_ + work_insn_idx_;
+          const Instruction* inst = Instruction::At(insns);
+          int opcode_flags = Instruction::FlagsOf(inst->Opcode());
 
-        if ((opcode_flags & Instruction::kThrow) == 0 && CurrentInsnFlags()->IsInTry()) {
-          saved_line_->CopyFromLine(work_line_.get());
+          if ((opcode_flags & Instruction::kThrow) == 0 && CurrentInsnFlags()->IsInTry()) {
+            saved_line_->CopyFromLine(work_line_.get());
+          }
         }
       }
       break;
@@ -1236,6 +1241,9 @@
     PrependToLastFailMessage(prepend);
     return false;
   }
+  // We may have a runtime failure here, clear.
+  have_pending_runtime_throw_failure_ = false;
+
   /* Perform code flow verification. */
   if (!CodeFlowVerifyMethod()) {
     DCHECK_NE(failures_.size(), 0U);
diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt
index 80b4f57..2196a88 100644
--- a/test/800-smali/expected.txt
+++ b/test/800-smali/expected.txt
@@ -22,4 +22,5 @@
 b/21863767
 b/21886894
 b/22080519
+b/21645819
 Done!
diff --git a/test/800-smali/smali/b_21645819.smali b/test/800-smali/smali/b_21645819.smali
new file mode 100644
index 0000000..195d662
--- /dev/null
+++ b/test/800-smali/smali/b_21645819.smali
@@ -0,0 +1,9 @@
+.class public LB21645819;
+.super Ljava/lang/Object;
+
+# The method declares a parameter of an inaccessible class. This should not abort/kill us.
+
+.method public static run(Lpkg/ProtectedClass;)V
+.registers 10
+       return-void
+.end method
\ No newline at end of file
diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java
index 337d0d9..e6f065e 100644
--- a/test/800-smali/src/Main.java
+++ b/test/800-smali/src/Main.java
@@ -91,6 +91,8 @@
                 null));
         testCases.add(new TestCase("b/22080519", "B22080519", "run", null,
                 new NullPointerException(), null));
+        testCases.add(new TestCase("b/21645819", "B21645819", "run", new Object[] { null },
+                null, null));
     }
 
     public void runTests() {
diff --git a/test/800-smali/src/pkg/ProtectedClass.java b/test/800-smali/src/pkg/ProtectedClass.java
new file mode 100644
index 0000000..b262155
--- /dev/null
+++ b/test/800-smali/src/pkg/ProtectedClass.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package pkg;
+
+class ProtectedClass {
+}